package com.socodethis.spaceex;

import java.util.ArrayList;

import com.badlogic.gdx.Gdx;
import com.socodethis.spaceex.math.cPoint;



	//This class was made as a more elegant solution to the original shortest path algo
	public class shortestPath {
		ArrayList<cPoint> _path = new ArrayList<cPoint>();
		int[][] masterMap, movementMap;
		int tileWidth,tileHeight, movementSquares;
		private cPoint start,end;
		private int x,y;
		private ArrayList<cPoint> _steps;
		private boolean didSomething,stepFound;
		private int count, increment, build;
		private cPoint current = new cPoint(0,0);
		//levelMap is a map showing the difficulty of terrain to pass over. 0 = wall. all other numbers describe difficulty of the terrain
		public shortestPath(int[][] levelMap, cPoint start, cPoint end, int tileWidth, int tileHeight){
			//System.out.println("Shortest Path");
			this.movementSquares = tileWidth*tileHeight;
			this.tileWidth = tileWidth;
			this.tileHeight = tileHeight;
			masterMap = new int[tileWidth][tileHeight];
			movementMap = new int[tileWidth][tileHeight];
			for(int y = 0; y < tileHeight; y++){
				for(int x = 0; x<tileWidth;x++){
					//Avoid walls
					if (levelMap[x][y]==0 && !(end.getX()==x && end.getY()==y)){
						masterMap[x][y] = -1;
					}else if((start.getX()==x && start.getY()==y)){
						masterMap[x][y] = 1;
					}else{
						masterMap[x][y] = 0;
					}
					//If there is an exit, mark it as no movement penalty
					if(levelMap[x][y] == -1){
						movementMap[x][y] = 1;
					}else{
						movementMap[x][y] = levelMap[x][y];
					}
					//System.out.print(masterMap[x][y]);
				}
				//System.out.println();
			}
			this.start = start;
			this.end = end;
			//Gdx.app.log("shortestPath","Initialized ");
		}
		public boolean returnUncounted(){
			for(int y = 0; y<tileHeight;y++){
				for(int x = 0; x< tileWidth;x++){
					if(masterMap[(int) end.getX()][(int) end.getY()] == 0){
						return true;
					}
				}
			}
			return false;
		}
		public cPoint getStart(){
			return start;
		}
		public cPoint getEnd(){
			return end;
		}
		public void setNewPath(cPoint start, cPoint end){
			this.start = new cPoint(start);
			this.end = new cPoint(end);
		}
		
		public ArrayList<cPoint> returnPath(){
			//This map solver uses a waterfall algorithm, which has far better time than the best-first I had in place previously
			_steps = new ArrayList<cPoint>();
			count = 1;
			increment = 0;
			while(returnUncounted()){
				didSomething = false;
				//System.out.println("Building Loop");
				for(y = 0; y< tileHeight; y++){
					for(x = 0; x<tileWidth;x++){
						if(masterMap[x][y] == count){
							if(x != 0){
								if(masterMap[x-1][y] == 0){
									masterMap[x-1][y] += (count+movementMap[x-1][y]);
									didSomething = true;
								}
							}
							if (y != 0){
								if(masterMap[x][y-1] == 0){
									masterMap[x][y-1] += (count+movementMap[x][y-1]);
									didSomething = true;
								}
							}
							if (x != tileWidth-1){
								if(masterMap[x+1][y] == 0){
									masterMap[x+1][y] += (count+movementMap[x+1][y]);
									didSomething = true;
								}
							}
							if (y != tileHeight-1){
								if(masterMap[x][y+1] == 0){
									masterMap[x][y+1] += (count+movementMap[x][y+1]);
									didSomething = true;
								}
							}
						}
					}
				}
				//If you can't find anywhere else to go, and the increment is way too high, return just the starting point
				if(!didSomething && increment == movementSquares){
					//Gdx.app.log("shortestPath","Error. Returning. ");
					_steps.add(start);
					return _steps;
				}else if (!didSomething){
					increment++;
				}else{
					increment = 0;
				}
				count++;
			}
			//Gdx.app.log("shortestPath","Count Taken.");
			build = masterMap[(int) end.getX()][(int) end.getY()];
			stepFound = false;
			current.setPoint(end.getX(), end.getY());
			_steps.add(0, current);
			while(build>1){
				//System.out.println("Backtracking...");
				//System.out.println("Build: " + build);
				//System.out.println(current.x + " " + current.y);
				if(current.getX() != 0 && !stepFound){
					if(masterMap[(int) (current.getX()-1)][(int) current.getY()] == build-1){
						current = new cPoint(current.getX()-1,current.getY());
						stepFound = true;
					}
				}
				if (current.getY() != 0 && !stepFound){
					if(masterMap[(int) current.getX()][(int) (current.getY()-1)] == build-1){
						current = new cPoint(current.getX(),current.getY()-1);
						stepFound = true;
					}
				}
				if (current.getX() != tileWidth-1 && !stepFound){
					if(masterMap[(int) (current.getX()+1)][(int) current.getY()] == build-1){
						current = new cPoint(current.getX()+1,current.getY());
						stepFound = true;
					}
				}
				if (current.getY() != tileHeight-1 && !stepFound){
					if(masterMap[(int) current.getX()][(int) (current.getY()+1)] == build-1){
						current = new cPoint(current.getX(),current.getY()+1);
						stepFound = true;
					}
				}
				if(stepFound){
					stepFound = false;
					_steps.add(0, current);
				}
				build--;
			}
			//Gdx.app.log("shortestPath","Algo Completed. Returning. ");
			//System.out.println("Steps: " + _steps.size());
			return _steps;
		}
	}

